HDU 5812 Distance(数学、约数枚举)
题意:
$维护1个集合S,d(x, y):=x经过多少次 乘/除素数 变成y$
$给定Q\le 10^5个操作,有三种类型$
$1 x:插入x,若x存在则无视$
$2 x:删除x,若x不存在则无视$
$3 x:求min_{y\in S} \{ d(x, y) \}$
分析:
$令f(x)=x中质因子的个数,首先发现d(x, y)=f(x/gcd(a, b))+f(y/gcd(a, b))$
$所以我们可以枚举x的约数d,对于所有是d的倍数的y,求min\{ f(y/d) \}$
$我们可以用multiset来维护(约数, 他的倍数的质因子个数)对$
$对于每次插入x,枚举x的约数d,插入(d, f(x/d))即可,删除同理$
$查询只需要枚举x的约数d,lower bound d对于的最小f(x/d)就好$
$时间复杂度O(q\times max\{d(A_i)\})$
//
// Created by TaoSama on 2016-08-09
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int q;
vector<int> primes;
int g[N];
void gao() {
for(int i = 1; i < N; ++i) g[i] = i;
for(int i = 2; i < N; ++i) {
if(g[i] == i) primes.push_back(i);
for(int j = 0; j < primes.size() && i * primes[j] < N; ++j) {
g[i * primes[j]] = primes[j];
if(i % primes[j] == 0) break;
}
}
}
vector<int> divisors[N];
vector<pair<int, int> > factors[N];
int cnt[N];
int factorize(int x) {
if(cnt[x]) return cnt[x];
int y = x;
auto& v = factors[y];
while(x > 1) {
int t = g[x];
int e = 0;
while(g[x] == t) ++e, x /= t;
v.push_back({t, e});
cnt[y] += e;
}
return cnt[y];
}
void dfs(int x, int k, int d) {
if(k == factors[x].size()) {
divisors[x].push_back(d);
return;
}
dfs(x, k + 1, d);
auto& p = factors[x][k];
for(int i = 0; i < p.second; ++i) {
d *= p.first;
dfs(x, k + 1, d);
}
}
void decomp(int x) {
if(divisors[x].size()) return;
factorize(x);
dfs(x, 0, 1);
}
bool vis[N];
multiset<pair<int, int> > mf; //number of factors of the number's multiple
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\1004.in", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt", "w", stdout);
#endif
ios_base::sync_with_stdio(0);
gao();
while(scanf("%d", &q) == 1 && q) {
static int kase = 0;
printf("Case #%d:\n", ++kase);
mf.clear();
memset(vis, 0, sizeof vis);
for(int i = 1; i <= q; ++i) {
char op[2]; int x; scanf("%s%d", op, &x);
if(*op == 'I') {
if(vis[x]) continue;
vis[x] = true;
decomp(x);
for(auto& div : divisors[x]) {
int num = factorize(x / div);
mf.insert({div, num});
}
} else if(*op == 'D') {
if(!vis[x]) continue;
vis[x] = false;
decomp(x);
for(auto& div : divisors[x]) {
int num = factorize(x / div);
mf.erase(mf.find({div, num}));
}
} else {
if(!mf.size()) {
puts("-1");
continue;
}
decomp(x);
int ans = INF;
for(auto& div : divisors[x]) {
auto iter = mf.lower_bound({div, -INF});
if(iter != mf.end() && iter->first == div) {
int num = factorize(x / div);
ans = min(ans, num + iter->second);
}
}
printf("%d\n", ans);
}
}
}
return 0;
}